package org.multithreadprint;

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * Copyright (c) 2023-2033 All Rights Reserved
 * 方法 2
 * 题目：三个线程分别打印 A，B，C，要求这三个线程一起运行，打印 n 次，按顺序输出形如“ABCABCABC....”的字符串。
 * 方法：通过 ReentrantLock 加锁控制并发，通过 lock.Condition 实现精确通知，线程状态条件不满足时等待，条件满足时唤醒，控制执行顺序。
 * 实现：
 *      1. Condition 对象由 lock 对象创建，在调用前必须先获取锁
 *      2. Condition 主要通过 await() signal() 方法实现精确通知
 *
 * @date: 2023/7/14
 */
public class MultiThreadLockCondition {
    private int times;
    private int status;

    private static Lock lock = new ReentrantLock();
    private static Condition condition0 = lock.newCondition();
    private static Condition condition1 = lock.newCondition();
    private static Condition condition2 = lock.newCondition();

    MultiThreadLockCondition(int times) {
        this.times = times;
    }

    public static void main(String[] args) {
        MultiThreadLockCondition multiThreadLockCondition = new MultiThreadLockCondition(3);

        new Thread(() -> {
            multiThreadLockCondition.printLetter(0, condition0, condition1, "A");
        }).start();

        new Thread(() -> {
            multiThreadLockCondition.printLetter(1, condition1, condition2, "B");
        }).start();

        new Thread(() -> {
            multiThreadLockCondition.printLetter(2, condition2, condition0, "C");
        }).start();
    }

    private void printLetter(int flag, Condition current, Condition next, String letter) {
        for (int i = 0; i < times; ) {
            lock.lock();
            try {
                if (status % 3 != flag) {
                    current.await();
                } else {
                    System.out.print(letter);
                    status++;
                    next.signal();
                    i++;
                }
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                lock.unlock();
            }
        }
    }
}
